package com.world.cat.service.sys;

import com.world.cat.app.AppConstant;
import com.world.cat.app.utils.AppUtils;
import com.world.cat.dao.sys.ApiDetailDao;
import com.world.cat.model.sys.ApiDetail;
import com.world.cat.service.generate.FieldService;
import com.world.common.generate.auto.QApi;
import com.world.common.generate.auto.QField;
import com.world.common.generate.auto.QFieldInfo;
import com.world.common.pojo.Result;
import com.world.common.pojo.api.ApiInterface;
import com.world.common.pojo.api.ApiReqParameter;
import com.world.common.pojo.api.ApiResParameter;
import com.world.common.pojo.tree.ZTreeNode;
import com.world.common.util.CollectionUtil;
import com.world.common.util.SysUtil;
import com.world.core.dao.GenericRepository;
import org.apache.commons.lang.ArrayUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;

import javax.annotation.Resource;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Parameter;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

@Service
@Transactional
public class ApiDetailService extends BaseService<ApiDetail> {
    private static Map<String, Method> apiMethodMap = new ConcurrentHashMap<>();

    @Resource
    private ApiDetailDao apiDetailDao;

    @Override
    public GenericRepository getDao() {
        return apiDetailDao;
    }

    public ZTreeNode getDocTree(String username, String roleId) {
        ZTreeNode rootNode = new ZTreeNode();
        rootNode.setId("0");
        rootNode.setName("根");
        List<Class> controllerClasses = AppUtils.getAllControllerClass(AppConstant.api_controller_pattern);
        if (CollectionUtil.isNotEmpty(controllerClasses)) {
            for (Class controllerClass : controllerClasses) {
                RequestMapping annotation = (RequestMapping) controllerClass.getAnnotation(RequestMapping.class);
                if (annotation != null && ArrayUtils.isNotEmpty(annotation.value())) {
                    String baseUrl = annotation.value()[0];
                    String controllerName = annotation.name();
                    boolean checkedParent = false;
                    ZTreeNode zTreeNode = new ZTreeNode(baseUrl, "0", controllerName, checkedParent, true, null);
                    if (AppUtils.ifControl(annotation.name())) {
                        Method[] methods = controllerClass.getDeclaredMethods();
                        if (ArrayUtils.isNotEmpty(methods)) {
                            for (Method method : methods) {
                                RequestMapping requestMapping = method.getAnnotation(RequestMapping.class);
//                                ResponseBody responseBody = method.getAnnotation(ResponseBody.class);
                                if (requestMapping != null && ArrayUtils.isNotEmpty(requestMapping.value())) {
                                    String fullUrl = baseUrl + requestMapping.value()[0];
                                    apiMethodMap.put(fullUrl, method);
                                    if (AppUtils.ifControl(requestMapping.name())) {
                                        String name = requestMapping.name();
                                        boolean checkedChild = false;
                                        ZTreeNode zTreeNodeUrl = new ZTreeNode(fullUrl, baseUrl, name, checkedChild, true, null);
                                        zTreeNode.getChildren().add(zTreeNodeUrl);
                                    }
                                }
                            }
                        }
                    }

                    if (CollectionUtil.isNotEmpty(zTreeNode.getChildren())) {
                        rootNode.getChildren().add(zTreeNode);
                    }
                }
            }
        }

        return rootNode;
    }

    public ApiInterface getInterfaceDetail(String url) {
        ApiInterface apiInterface = new ApiInterface();
        Method method = apiMethodMap.get(url);
        if (method != null) {
            RequestMapping requestMapping = method.getAnnotation(RequestMapping.class);
            ResponseBody responseBody = method.getAnnotation(ResponseBody.class);
            apiInterface.setName(requestMapping.name());
            apiInterface.setAddress(url);
            apiInterface.setReturnType("json");
            apiInterface.setRequestType("post");
            List<ApiReqParameter> apiReqParameters = new ArrayList<>();
            apiInterface.setApiReqParameters(apiReqParameters);
            Parameter[] parameters = method.getParameters();
            for (Parameter parameter : parameters) {
                List<QFieldInfo> qFieldInfos = FieldService.getAllFieldInfo(parameter.getType());
                if (CollectionUtil.isNotEmpty(qFieldInfos)) {
                    for (QFieldInfo qFieldInfo : qFieldInfos) {
                        ApiReqParameter apiReqParameter = new ApiReqParameter();
                        apiReqParameter.setType(qFieldInfo.getJavaFiledType());
                        apiReqParameter.setNick(qFieldInfo.getNickname());
                        apiReqParameter.setName(qFieldInfo.getName());
                        apiReqParameter.setMust(qFieldInfo.getNullable() ? "否" : "是");
                        apiReqParameter.setDesc(qFieldInfo.getNickname());
                        apiReqParameters.add(apiReqParameter);
                    }
                } else {
                    ApiReqParameter apiReqParameter = new ApiReqParameter();
                    apiReqParameter.setType(parameter.getType().getSimpleName());
                    apiReqParameter.setName(parameter.getName());

                    apiReqParameters.add(apiReqParameter);
                }
            }

            List<ApiResParameter> apiResParameters = new ArrayList<>();
            apiInterface.setApiResParameters(apiResParameters);
            apiResParameters.addAll(getResParameters(Result.class, false));
            QApi qApi = method.getAnnotation(QApi.class);
            if (qApi != null) {
                Class<?> resDataType = qApi.dataClass();
                apiResParameters.addAll(getResParameters(resDataType, false));
            }

        }
        ApiDetail apiDetail = apiDetailDao.findByUrl(url);
        if (apiDetail != null) {
            apiInterface.setResExample(apiDetail.getResExample());
            apiInterface.setReqExample(apiDetail.getReqExample());
        }

        return apiInterface;
    }

    private List<ApiResParameter> getResParameters(Class clazz, boolean space) {
        List<ApiResParameter> apiResParameters = new ArrayList<>();
        Field[] fields = clazz.getDeclaredFields();
        for (Field field : fields) {
            QField qField = field.getAnnotation(QField.class);
            if (qField != null) {
                QFieldInfo fieldInfo = new QFieldInfo();
                fieldInfo.fromQField(field, qField);
                ApiResParameter apiResParameter = new ApiResParameter();

                apiResParameter.setType(fieldInfo.getJavaFiledType());
                apiResParameter.setNick(fieldInfo.getNickname());
                apiResParameter.setName(fieldInfo.getName());
                apiResParameter.setDesc(fieldInfo.getNickname());
                apiResParameter.setSpace(space);

                apiResParameters.add(apiResParameter);
                QApi qApi = field.getAnnotation(QApi.class);
                if (qApi != null) {
                    apiResParameters.addAll(getResParameters(qApi.dataClass(), true));
                }
            }
        }
        return apiResParameters;
    }
}
